<?php

namespace app\api\controller;

use think\Db;
use think\Hook;
use fast\Random;
use think\Validate;
use app\common\model\Config;
use app\common\controller\Api;
use addons\workorder\model\Kbs;
use addons\workorder\model\Orders;
use addons\workorder\model\Engineer;
use addons\workorder\library\General;
use app\admin\model\workorder\Fields;
use addons\workorder\library\Captcha;

/**
 * 工单系统API
 */
class Workorder extends Api
{
    protected $noNeedLogin = ['login', 'captcha', 'captchaPre'];

    protected $noNeedRight = ['*'];

    /**
     * @var General 实例
     */
    protected $General        = null;
    protected $pageCount      = 15;
    protected $userEngineerId = null;

    public function _initialize()
    {
        parent::_initialize();

        $this->General = General::instance();

        // 当前用户是否是工程师
        if ($this->auth) {
            $this->userEngineerId = Engineer::where('user_id', $this->auth->id)->where('status', '1')->value('id');
        }

        $this->General->autoClose();
    }

    public function index()
    {
        $this->success('', [
            'engineer' => $this->userEngineerId ? true : false
        ]);
    }

    public function login()
    {
        $username  = $this->request->post('username');
        $password  = $this->request->post('password');
        $captcha   = $this->request->post('captcha');
        $captchaId = $this->request->post('captcha_id');

        $rule = [
            'captcha'    => 'require|length:4,6',
            'username'   => 'require|length:3,30',
            'password'   => 'require|length:6,30',
            'captcha_id' => 'require'
        ];
        $msg  = [
            'captcha.require'    => 'Please enter the verification code',
            'captcha.length'     => 'Please enter the correct verification code~',
            'username.require'   => 'User name cannot be empty',
            'username.length'    => 'User name must be 3 to 30 characters',
            'password.require'   => 'Password cannot be empty',
            'password.length'    => 'The password must be between 3 and 30 characters',
            'captcha_id.require' => 'Missing parameter!'
        ];
        $data = [
            'username'   => $username,
            'password'   => $password,
            'captcha'    => $captcha,
            'captcha_id' => $captchaId
        ];

        $captchaObj = new Captcha();
        if (!$captchaObj->check($captcha, $captchaId)) {
            $this->error(__('Please enter the correct verification code~'));
        }

        $validate = new Validate($rule, $msg);
        $result   = $validate->check($data);
        if (!$result) {
            $this->error(__($validate->getError()));
        }

        $ret = $this->auth->login($username, $password);
        if ($ret) {
            $data                       = ['userinfo' => $this->auth->getUserinfo()];
            $data['userinfo']['avatar'] = cdnurl($data['userinfo']['avatar'], true);
            $this->success(__('Logged in successful'), $data);
        } else {
            $this->error($this->auth->getError());
        }
    }

    public function captchaPre()
    {
        $captchaId = md5(Random::uuid());
        $this->success('', [
            'captcha_id' => $captchaId
        ]);
    }

    public function captcha()
    {
        $captchaId = $this->request->request('captcha_id');
        $config    = array(
            'codeSet'  => '123456789',            // 验证码字符集合
            'fontSize' => 22,                     // 验证码字体大小(px)
            'useCurve' => false,                  // 是否画混淆曲线
            'useNoise' => true,                   // 是否添加杂点
            'length'   => 4,                      // 验证码位数
            'bg'       => array(255, 255, 255),   // 背景颜色
        );
        $captcha   = new Captcha($config);
        return $captcha->entry($captchaId);
    }

    public function manage()
    {
        if (!$this->userEngineerId) {
            $this->error(__('You have no permission to operate!'));
        }

        $page = $this->request->param('page') ?? 1;
        $type = $this->request->param('type') ?? '0';
        $out_trade_no = $this->request->param('out_trade_no') ?? '';
        $min  = ($page == 1) ? 0 : (($page - 1) * $this->pageCount);

        $where['orders.engineer_id'] = $this->userEngineerId;
        switch ($type) {
            case '1':
                $where['orders.status'] = ['in', '1,2'];
                break;
            case '2' :
                $where['orders.status'] = 3;
                break;
            case '3':
                $where['orders.status'] = ['in', '4,5'];
                break;
        }
        if ($out_trade_no) {
            $where['orders.out_trade_no'] = $out_trade_no;
        }

        $orders = Orders::where($where)
            ->with(['category', 'urgentrank', 'user'])
            ->order('createtime desc')
            ->limit($min, $this->pageCount)
            ->select();

        foreach ($orders as $key=>$item) {
            //print_r(date('Y-m-d H:i:s', $item->createtime));exit;
            //$orders->ceatetime = date('Y-m-d H:i:s', $item->createtime);
            $item->getRelation('category')->visible(['logo_image']);
            $item->getRelation('urgentrank')->visible(['name']);
            $item->getRelation('user')->visible(['nickname']);
            $item->status = $this->General->handleStatus($item->status, true);
            $item->title  = $item->title ?? __('Untitled');

            if ($item->category->logo_image) {
                $item->logo_image = cdnurl($item->category->logo_image, true);
                unset($item->category);
            }
        }

        $this->success('ok', [
            'type'   => $type,
            'page'   => $page,
            'orders' => $orders,
            'next'   => !(count($orders) < $this->pageCount)
        ]);
    }

    public function searchTransfer()
    {
        $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
        $word    = (array)$this->request->request("q_word/a");
        $keyword = $this->request->param("keyword") ?? false;
        if ($keyword) {
            if (strpos($keyword, ' ') !== false) {
                $word = explode(' ', $keyword);
            } else {
                $word[] = $keyword;
            }
        }

        $engineers = Engineer::all(function ($query) use ($word) {
            $word = array_filter(array_unique($word));
            if (count($word) == 1) {
                $query->where('title', "like", "%" . reset($word) . "%");
            } else {
                $query->where(function ($query) use ($word) {
                    foreach ($word as $item) {
                        $query->whereOr(function ($query) use ($item) {
                            $query->where('title', "like", "%{$item}%");
                        });
                    }
                });
            }
            $query->where('status', '1');
            $query->where('user_id', '<>', $this->auth->id);
        });
        return json(['list' => $engineers, 'total' => count($engineers)]);
    }

    public function transfer()
    {
        $id  = $this->request->param('id');
        $row = Orders::get($id);
        if (!$row) {
            $this->error(__('Work order not found~'));
        }
        $isCurrentEngineer = $row->engineer_id === $this->userEngineerId;
        if (!$isCurrentEngineer) {
            $this->error(__('You have no permission to operate!'));
        }

        if ($this->request->isPost()) {
            $param = $this->request->param();
            $res   = $this->General->transfer($row, $param['transfer_engineer']);
            if ($res['code'] == 1) {
                $this->output($res);
            } else {
                $this->error($res['msg']);
            }
        }

        $this->success('ok', [
            'info' => $row
        ]);
    }

    public function userInfo()
    {
        $id         = $this->request->param('id');
        $userId     = $this->request->param('user_id') ?? 0;
        $engineerId = $this->request->param('engineer_id') ?? 0;

        $row = Orders::get($id, ['user']);
        if (!$row) {
            $this->error(__('Work order not found~'));
        }

        if ($userId && $row['user_id'] == $userId) {
            $userInfo = [
                'nickname' => $row->user->nickname,
                'avatar'   => $row->user->avatar ? cdnurl($row->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($row->user->nickname) : cdnurl('/assets/img/avatar.png', true)),
                'bio'      => $row->user->bio,
                'id'       => $row->user->id
            ];
        } elseif ($engineerId) {
            $engineer = Engineer::get($engineerId, ['user']);
            if (!$engineer) {
                $this->error(__('engineer not found~'));
            }
            $userInfo           = $engineer;
            $userInfo['email']  = $engineer->user->email;
            $userInfo['mobile'] = $engineer->user->mobile;
            $userInfo['avatar'] = $engineer->user->avatar ? cdnurl($engineer->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($engineer->user->nickname) : cdnurl('/assets/img/avatar.png', true));
            unset($userInfo['user'], $userInfo['openid'], $userInfo['work_order_quantity']);
        } else {
            $this->error(__('user not found~'));
        }

        $this->success('ok', [
            'userinfo' => $userInfo
        ]);
    }

    public function my()
    {
        $page = $this->request->param('page') ?? 1;
        $min  = ($page == 1) ? 0 : (($page - 1) * $this->pageCount);

        if ($this->request->isDelete()) {
            $order_id = (int)$this->request->param('order_id');
            $order    = Orders::get($order_id);
            if (!$order) {
                $this->error(__('Work order not found~'));
            }
            if ($order->status != 5) {
                $this->error(__('You can delete a work order after closing it!'));
            }
            if (Orders::destroy(['id' => $order_id, 'user_id' => $this->auth->id])) {
                General::orderNumberChangeCalcEngineerStatistics($order->id, $order->engineer_id, 'del');
                $this->success(__('Delete Success~'));
            } else {
                $this->error(__('Delete Fail!'));
            }
        }

        $this->relationSearch = true;
        $orders               = Orders::where('user_id', $this->auth->id)
            ->with(['category', 'urgentrank'])
            ->order('createtime desc')
            ->limit($min, $this->pageCount)
            ->select();

        foreach ($orders as $item) {
            $item->getRelation('category')->visible(['logo_image']);
            $item->getRelation('urgentrank')->visible(['name']);
            $item->status = $this->General->handleStatus($item->status);
            $item->title  = $item->title ?? __('Untitled');

            if ($item->category->logo_image) {
                $item->logo_image = cdnurl($item->category->logo_image, true);
                unset($item->category);
            }
        }

        $this->success('ok', [
            'page'   => $page,
            'orders' => $orders,
            'next'   => !(count($orders) < $this->pageCount)
        ]);
    }

    public function detail()
    {
        $id  = $this->request->param('id');
        $row = Orders::get($id, ['user', 'category', 'urgentrank']);
        if (!$row) {
            $this->error(__('Work order not found~'));
        }

        $isUser            = $row->user_id == $this->auth->id;
        $isCurrentEngineer = $row->engineer_id === $this->userEngineerId;
        if (!$isUser && !$isCurrentEngineer) {
            $this->error(__('You have no permission to operate!'));
        }

        if ($this->request->isPost()) {
            $type = $this->request->param('type');
            if ($type == 'close') {
                $this->output($this->General->closeOrder($row, $isCurrentEngineer));
            } elseif ($type == 'urging' && $isUser) {
                $this->output($this->General->urgingOrder($row));
            } elseif ($type == 'evaluate') {
                if ($row['status'] == 1) {
                    $this->error(__('The current status of the work order cannot be evaluated~'));
                }
                if ($row['status'] == 5) {
                    $this->error(__('The work order has been evaluated~'));
                }
                $this->success('ok', [
                    'info' => $row
                ]);
            }
            $this->error(__('Nothing happened~'));
        }

        $orderInfo = $this->General->orderInfoHandle($row, $isUser, $isCurrentEngineer);
        foreach ($orderInfo['basicField'] as &$value) {
            $value['value'] = strip_tags($value['value']);
        }

        // 聊天记录和工程师资料
        $records    = $this->General->orderRecords($id, $row->engineer_id);
        $replyField = $row->getFields(null, $isUser ? 1 : 2);

        $this->success('ok', [
            'row'        => $orderInfo['order'],
            'isUser'     => $isUser,
            'fields'     => $replyField,
            'records'    => $records['records'],
            'title'      => $orderInfo['order']->title . ' – ' . __('Work order details'),
            'basicField' => $orderInfo['basicField']
        ]);
    }

    public function evaluate()
    {
        $id    = $this->request->param('id');
        $order = Orders::get($id);

        if (!$order) {
            $this->error(__('Work order not found~'));
        }
        if ($order->status == 1) {
            $this->error(__('The current status of the work order cannot be evaluated~'));
        }
        if ($order->status == 5) {
            $this->error(__('The work order has been evaluated~'));
        }

        if ($this->request->isPost()) {
            $row = $this->request->param();
            unset($row['id']);
            $this->output($this->General->createEvaluate($order, $row, $this->auth->id));
        }
    }

    public function reply()
    {
        $row   = $this->request->param();

        if(isset($row['reply_attachment'] ) && !empty($row['reply_attachment'])){
            $complain_info = db('workorder_orders')->where('id',$row['id'])->find();

            $attachment   = explode(',', trim($row['reply_attachment'], ','));
            $complain = new Complain();
            $imgurl = [];
            foreach ($attachment as $key => $item) {
                $imgurl[] = $complain->uploadImg($item,$complain_info['complainted_mchid']);
            }
            $row['media_id'] = implode(',', $imgurl);

        }
        $order = Orders::get($row['id']);
        if (!$order) {
            $this->error(__('Work order not found~'));
        }

        $user     = ($order->user_id == $this->auth->id) ? $this->auth : false;
        $engineer = ($order->engineer_id == $this->userEngineerId) ? Engineer::get($this->userEngineerId) : false;
        if (!$user && !$engineer) {
            $this->error(__('You have no permission to operate!'));
        }

        $res = $this->General->createReply($order, $user, $engineer, $row);

        if ($res['code'] == 1) {
            $this->success($res['msg'], [
                'records' => $res['data']['records']
            ]);
        } else {
            $this->error($res['msg']);
        }
    }

    public function showConfidential()
    {
        $id = $this->request->param('id');
        // 直接读取数据库中的数据
        $row = Db::name('workorder_records')
            ->where('id', $id)
            ->find();
        if (!$row) {
            $this->error(__('Record order not found!'));
        }

        $order             = Orders::get($row['order_id']);
        $isUser            = $order->user_id == $this->auth->id;
        $isCurrentEngineer = $order->engineer_id === $this->userEngineerId;
        if (!$isUser && !$isCurrentEngineer) {
            $this->error(__('You have no permission to operate!'));
        }

        $this->success('ok', $row);
    }

    public function category()
    {
        $category = Db::name('workorder_category')
            ->where('status', 1)
            ->where('deletetime', null)
            ->order('weigh desc')
            ->select();

        foreach ($category as $item) {
            $pid                = $item['pid'];
            $item['logo_image'] = cdnurl($item['logo_image'], true);

            if ($pid == 0) {
                $categoryList[] = $item;
            } else {
                $categoryChildTemp[$pid][] = $item;
            }
        }
        foreach ($categoryList as $index => $item) {
            $categoryList[$index]['child'] = $categoryChildTemp[$item['id']] ?? [];
        }

        $this->success('ok', [
            'category' => $categoryList
        ]);
    }

    public function search()
    {
        $type     = $this->request->param('type') ?? 'category';
        $page     = $this->request->param('page') ?? 1;
        $keywords = $this->request->param('keywords') ?? false;

        $min = ($page == 1) ? 0 : (($page - 1) * $this->pageCount);

        if ($type == 'category') {
            $category = Db::name('workorder_category')
                ->where('status', 1)
                ->where('pid', '>', 0)
                ->where('name', 'like', '%' . $keywords . '%')
                ->where('deletetime', null)
                ->order('weigh desc')
                ->limit($min, $this->pageCount)
                ->select();
            foreach ($category as $key => $item) {
                $category[$key]['logo_image'] = cdnurl($item['logo_image'], true);
            }

            $this->success('ok', [
                'res'  => $category,
                'page' => $page,
                'next' => !(count($category) < $this->pageCount)
            ]);
        }
    }

    public function kbs()
    {
        $keywords = $this->request->param('keywords') ?? false;
        $category = $this->request->param('category') ?? 0;

        $kbsIds = Db::name('workorder_category')
            ->where('id', $category)
            ->where('status', '1')
            ->where('deletetime', null)
            ->value('kbs_ids');

        $kbs = [];
        if ($kbsIds) {
            $where['id']         = ['in', $kbsIds];
            $where['status']     = '1';
            $where['deletetime'] = null;
            if ($keywords) {
                $where['title'] = ['like', '%' . $keywords . '%'];
            }

            $kbs = Db::name('workorder_kbs')
                ->field('id,title,views,likes,url')
                ->where($where)
                ->order('weigh desc')
                ->limit($this->pageCount)
                ->select();
        }

        $submitChannel = Db::name('workorder_submit_channel')
            ->where('status', 1)
            ->order('weigh desc')
            ->select();
        foreach ($submitChannel as $index => $item) {
            $submitChannel[$index]['logo_image'] = cdnurl($item['logo_image'], true);
        }

        $this->success('ok', [
            'res'     => $kbs,
            'channel' => $submitChannel
        ]);
    }

    public function kbsInfo()
    {
        $id       = $this->request->param('id');
        $category = $this->request->param('category') ?? 0;
        $kbs      = Kbs::get(['id' => $id, 'status' => '1']);
        if (!$kbs) {
            $this->error(__('I cant find the knowledge~'));
        }
        $kbs->setInc('views', 1);
        $recKbs = $this->General->recKbs($id, $category);

        $this->success('ok', [
            'kbs' => $kbs,
            'rec' => $recKbs
        ]);
    }

    public function kbsOperate()
    {
        $id   = $this->request->param('id');
        $type = $this->request->param('type');
        $kbs  = Kbs::get(['id' => $id, 'status' => '1']);
        if (!$kbs) {
            $this->error(__('I cant find the knowledge~'));
        }

        if ($type == 'likes' || $type == 'dislikes') {
            $kbs->setInc($type);
            $this->success('ok');
        }
    }

    public function create()
    {
        $category = $this->request->param('category');

        $autofillFieldNames = Fields::where([
            'position' => 0,
            'autofill' => 1,
            'status'   => '1',
        ])->column('name');

        // 获取工单的自动填充资料
        $last_workorder = Db::name('workorder_orders')
            ->field($autofillFieldNames)
            ->where('user_id', $this->auth->id)
            ->where('deletetime', null)
            ->order('createtime', 'desc')
            ->find();

        $fields       = Orders::getFields($last_workorder, 0);
        $categoryName = Db::name('workorder_category')
            ->where('id', $category)
            ->where('status', '1')
            ->where('deletetime', null)
            ->value('name');
        if (!$categoryName) {
            $this->error(__('Product / service classification not found~'));
        }

        $urgentrank = Db::name('workorder_urgentrank')
            ->where('status', '1')
            ->where('deletetime', null)
            ->order('weigh desc')
            ->select();
        if (!$urgentrank) {
            $this->error(__('Emergency level of no work order available!'));
        }

        if ($this->request->isPost()) {
            $row = $this->request->param();
            unset($row['category']);
            $row['category_id'] = $category;
            $res                = $this->General->createOrder($row, $this->auth->id);
            if ($res['code'] == 1) {
                $this->success(__('Submitted successfully~'), [
                    'order_id' => $res['data']['id']
                ]);
            } else {
                $this->error($res['msg']);
            }
        }

        $this->success('create', [
            'fields'       => $fields,
            'urgentrank'   => $urgentrank,
            'categoryName' => $categoryName
        ]);
    }

    public function uploadMultipart()
    {
        // 获取上传配置
        $upload = Config::upload();
        Hook::listen("upload_config_init", $upload);

        $this->success('ok', [
            'uploadurl' => $upload['uploadurl'],
            'multipart' => (isset($upload['multipart']) && $upload['multipart']) ? $upload['multipart'] : false,
        ]);
    }

    /**
     * 输出方法返回结果
     */
    protected function output($res)
    {
        if ($res['code'] == 1) {
            $this->success($res['msg']);
        } else {
            $this->error($res['msg']);
        }
    }
}